package vo;

import org.apache.commons.beanutils.ConvertUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

public class BasePO implements java.io.Serializable, Cloneable {

    public Map<String, Object> toMap() {
        return toMap(false);
    }
    public Map<String, Object> toMap(boolean  isAll) {
        Map map = new HashMap();
        try {
            List<PropertyDescriptor> pds = descriptProperty(isAll);
            System.out.println(pds.size());
            for (PropertyDescriptor pd : pds) {
                Method method = pd.getReadMethod();
                if (method != null) {
                    Object o = method.invoke(this);
                    if(o==null){
                        continue;
                    }
                    map.put(pd.getName(),o);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    public void init() {
    }

    public void clear() {
        try {
            for (PropertyDescriptor pd : descriptProperty()) {
                Method method = pd.getWriteMethod();
                if (method != null) {
                    method.invoke(this, (Object) null);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        try {
            List<String> list = new ArrayList();
            for (PropertyDescriptor pd : descriptProperty()) {
                Method method = pd.getReadMethod();
                if (method != null) {
                    list.add(pd.getName() + "=" + method.invoke(this));
                }
            }
            return this.getClass().getName() + ":{" + list.stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.joining(",")) +"}";
        } catch (Exception e) {
            e.printStackTrace();
            return super.toString();
        }
    }

    private List<PropertyDescriptor> descriptProperty() throws Exception {
        return descriptProperty(false);
    }
    private List<PropertyDescriptor> descriptProperty(boolean  isAll) throws Exception {
        BeanInfo beanInfo = Introspector.getBeanInfo(this.getClass());
        PropertyDescriptor[] pp = beanInfo.getPropertyDescriptors();
        List<PropertyDescriptor> list = new ArrayList<>();
        if(isAll){
            for (PropertyDescriptor pd : pp) {
                if (!pd.getName().equals("serialVersionUID")) {
                    list.add(pd);
                }
            }
        } else {
            for (PropertyDescriptor pd : pp) {
                if (!pd.getName().equals("class")) {
                    list.add(pd);
                }
            }
        }
        return list;
    }


    /**
     * 把字符串中大写字母前加上下划线
     *
     * @param name
     * @return
     */

    private  String getUpper(String name, boolean... nativeFlag) {
        if (null!=nativeFlag &&nativeFlag.length>0&& nativeFlag[0]) {//更好的写法是if(ArrayUtils.isNotEmpty(nativeFlag),但这是框架级别代码尽量不要依赖第三方工具包
            StringBuffer temp = new StringBuffer();
            for (Integer i = 0; i < name.length(); i++) {
                char tempC = name.charAt(i);
                if (Character.isUpperCase(name.charAt(i))) {
                    temp.append("_");
                }
                temp.append(tempC);
            }
            return temp.toString().toUpperCase();
        }
        return name;
    }


    /**
     * map to bean
     * @param map
     * @param nativeFlag 需要去"-"改变首字母为大写时 ture ；和对象属性名相同时为false 或不传
     */
    public void fromMap(Map<String, Object> map, boolean... nativeFlag) {
        if (map == null || map.isEmpty()) {
            return;
        }
        try {
            for (PropertyDescriptor pd : descriptProperty()) {
                Method method = pd.getWriteMethod();
                if (method != null) {
                    String name = getUpper(pd.getName(), nativeFlag);
                    if(!map.containsKey(name)){
                        name=name.toLowerCase();
                    }
                    if (map.containsKey(name)) {
                        Object value = map.get(name);
                        if (value != null) {
                            Class t = method.getParameterTypes()[0];
                            if (!t.isAssignableFrom(value.getClass())) {
                                try {
                                    value = ConvertUtils.convert(value, t);
                                } catch (Exception e) {
                                    value = null;
                                }
                            }
                        }
                        try {
                            method.invoke(this, value);
                        } catch (Exception e) {
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
